<?php
namespace app\command;

use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\facade\Db;
use think\facade\Log;
use app\service\TopviewApiService;

class CheckProductAnyShootTasks extends Command
{
    protected function configure()
    {
        $this->setName('check:product-anyshoot-tasks')
            ->setDescription('检查ProductAnyShoot任务状态并更新数据库');
    }

    protected function execute(Input $input, Output $output)
    {
        $output->writeln('开始检查ProductAnyShoot任务状态...');
        
        try {
            $apiService = new TopviewApiService();
            
            // 查询需要检查的任务（待处理和图片生成中的任务）
            $processingTasks = Db::name('product_anyshoot_tasks')
                ->whereIn('status', [0,1]) // 0:待处理, 1:图片生成中
                ->where('create_time', '>', date('Y-m-d H:i:s', strtotime('-24 hours'))) // 只检查24小时内的任务
                ->select();
            
            if (empty($processingTasks)) {
                $output->writeln('没有需要检查的待处理或图片生成中任务');
                return;
            }
            
            $output->writeln('找到 ' . count($processingTasks) . ' 个需要检查的任务');
            
            $updatedCount = 0;
            $imageCompletedCount = 0;
            $imageFailedCount = 0;
            
            foreach ($processingTasks as $task) {
                try {
                    $output->writeln('检查任务: ' . $task['task_id'] . ' (当前状态: ' . $this->getStatusText($task['status']) . ')');
                    // Db::name('product_anyshoot_tasks')->where('id', $task['id'])->update(['status' => 1]);
                    // 根据模板选择v1或v2查询
                    if (($task['template_id'] ?? '') === 'background_v2') {
                        $apiResult = $apiService->queryProductBackgroundTask($task['task_id']);
                    } else {
                        $apiResult = $apiService->queryProductAnyShootReplaceImageTask($task['task_id']);
                    }
                    $updateData = [
                        'update_time' => date('Y-m-d H:i:s')
                    ];
                    
                    $statusChanged = false;
                    
                    if (isset($apiResult['status'])) {
                        switch ($apiResult['status']) {
                            case 'success':
                                // 图片生成成功，可以进入图转视频阶段
                                $updateData['status'] = 3; // 图转视频中（等待用户触发）
                                $updateData['image_complete_time'] = date('Y-m-d H:i:s');
                                Db::name('product_anyshoot_tasks')->where('id', $task['id'])->update(['status' => 1]);
                                // 保存结果图片 - 分别存储key和url
                                if (isset($apiResult['anyfitImages']) && !empty($apiResult['anyfitImages'])) {
                                    $keys = [];
                                    $urls = [];
                                    
                                    foreach ($apiResult['anyfitImages'] as $image) {
                                        // v2 文档 anyfitImages 仅提供 url；v1 可能有 key/url
                                        if (isset($image['key'])) {
                                            $keys[] = $image['key'];
                                        }
                                        $imgUrl = $image['url'] ?? null;
                                        var_dump($imgUrl);
                                        if ($imgUrl) {
                                            // 使用带重试机制的下载方法
                                            $imageContent = $this->downloadImageWithRetry($imgUrl);
                                            
                                            if ($imageContent === false) {
                                                $output->writeln("    下载图片失败（已重试）: {$imgUrl}");
                                                continue;
                                            }
                                            
                                            $tempFile = tempnam(sys_get_temp_dir(), 'img_');
                                            file_put_contents($tempFile, $imageContent);
                                            try {
                                                $objectName = 'product_anyshoot/images/' . date('Ymd') . '/' . uniqid() . '.jpg';
                                                $ossService = new \app\service\OssService();
                                                $ossUrl = $ossService->putObject($objectName, $tempFile);
                                                $urls[] = $ossUrl;
                                            } finally {
                                                @unlink($tempFile);
                                            }
                                        }
                                    }
                                    
                                    $updateData['result_image_keys'] = json_encode($keys);
                                    $updateData['result_image_urls'] = json_encode($urls);
                                }
                                
                                $statusChanged = true;
                                $imageCompletedCount++;
                                $output->writeln('  -> 图片生成完成，等待图转视频');
                                break;
                                
                            case 'fail':
                                $updateData['status'] = 2; // 图片生成失败
                                $updateData['error_msg'] = $apiResult['message'] ?? '图片生成失败';
                                $statusChanged = true;
                                $imageFailedCount++;
                                $output->writeln('  -> 图片生成失败: ' . $updateData['error_msg']);
                                break;
                                
                            case 'processing':
                                // 如果当前是待处理状态，更新为图片生成中
                                if ($task['status'] == 0) {
                                    $updateData['status'] = 1; // 图片生成中
                                    $statusChanged = true;
                                    $output->writeln('  -> 图片正在生成中');
                                } else {
                                    $output->writeln('  -> 图片仍在生成中');
                                }
                                break;
                                
                            default:
                                // 对于未知状态，如果是待处理状态，标记为图片生成中
                                if ($task['status'] == 0) {
                                    $updateData['status'] = 1; // 图片生成中
                                    $statusChanged = true;
                                    $output->writeln('  -> 未知状态: ' . $apiResult['status'] . '，标记为图片生成中');
                                } else {
                                    $output->writeln('  -> 未知状态: ' . $apiResult['status']);
                                }
                                break;
                        }
                    } else {
                        // 如果API没有返回状态信息，且当前是待处理状态，标记为图片生成中
                        if ($task['status'] == 0) {
                            $updateData['status'] = 1; // 图片生成中
                            $statusChanged = true;
                            $output->writeln('  -> API未返回状态信息，标记为图片生成中');
                        }
                    }
                    
                    // 更新数据库
                    if (!empty($updateData)) {
                        Db::name('product_anyshoot_tasks')
                            ->where('id', $task['id'])
                            ->update($updateData);
                        $updatedCount++;
                    }
                    
                    // 记录日志
                    if ($statusChanged) {
                        Log::info('ProductAnyShoot任务状态更新', [
                            'task_id' => $task['task_id'],
                            'old_status' => $task['status'],
                            'old_status_text' => $this->getStatusText($task['status']),
                            'new_status' => $updateData['status'] ?? $task['status'],
                            'new_status_text' => $this->getStatusText($updateData['status'] ?? $task['status']),
                            'api_status' => $apiResult['status'] ?? 'unknown'
                        ]);
                    }
                    
                } catch (\Exception $e) {
                    $output->writeln('  -> 检查任务失败: ' . $e->getMessage());
                    Log::error('检查ProductAnyShoot任务状态失败', [
                        'task_id' => $task['task_id'],
                        'error' => $e->getMessage()
                    ]);
                }
                
                // 避免请求过于频繁，每个任务间隔1秒
                sleep(1);
            }
            
            $output->writeln('检查完成！');
            $output->writeln("总计检查: " . count($processingTasks) . " 个任务");
            $output->writeln("更新记录: {$updatedCount} 个");
            $output->writeln("图片生成完成: {$imageCompletedCount} 个");
            $output->writeln("图片生成失败: {$imageFailedCount} 个");
            
            // 记录执行日志
            Log::info('ProductAnyShoot任务状态检查完成', [
                'total_checked' => count($processingTasks),
                'updated' => $updatedCount,
                'image_completed' => $imageCompletedCount,
                'image_failed' => $imageFailedCount
            ]);
            
            // 检查视频生成中的任务
            $videoTasks = Db::name('product_anyshoot_tasks')
                ->where('status', 4) // 图转视频中
                ->where('create_time', '>', date('Y-m-d H:i:s', strtotime('-24 hours')))
                ->select();

            $videoUpdatedCount = 0;
            $videoSuccessCount = 0;
            $videoFailedCount = 0;

            foreach ($videoTasks as $task) {
                try {
                    $output->writeln('检查视频任务: ' . $task['video_task_id'] . ' (当前状态: ' . $this->getStatusText($task['status']) . ')');
                    if (empty($task['video_task_id'])) {
                        $output->writeln('  -> video_task_id为空，跳过');
                        continue;
                    }
                    $apiResult = $apiService->queryCommonImage2VideoTask($task['video_task_id'], true);
                    $updateData = [
                        'update_time' => date('Y-m-d H:i:s')
                    ];
                    $statusChanged = false;
                    if (isset($apiResult['status'])) {
                        switch ($apiResult['status']) {
                            case 'success':
                                $updateData['status'] = 5; // 图转视频成功
                                $updateData['video_complete_time'] = date('Y-m-d H:i:s');
                                // 保存视频结果
                                if (isset($apiResult['videos']) && is_array($apiResult['videos'])) {
                                    $ossService = new \app\service\OssService();
                                    $processedVideos = [];
                                    
                                    foreach ($apiResult['videos'] as $video) {
                                        if (isset($video['originVideo']['filePath'])) {
                                            // 使用带重试机制的下载方法
                                            $videoUrl = $video['originVideo']['filePath'];
                                            $videoContent = $this->downloadVideoWithRetry($videoUrl);
                                            
                                            if ($videoContent === false) {
                                                throw new \Exception('下载视频失败: ' . $videoUrl);
                                            }
                                            
                                            // 生成OSS对象名
                                            $objectName = 'product_anyshoot/videos/' . date('Ymd') . '/' . uniqid() . '.mp4';
                                            
                                            // 创建临时文件
                                            $tempFile = tempnam(sys_get_temp_dir(), 'video_');
                                            if (file_put_contents($tempFile, $videoContent) === false) {
                                                throw new \Exception('保存临时视频文件失败');
                                            }
                                            
                                            try {
                                                // 上传到OSS
                                                $ossUrl = $ossService->putObject($objectName, $tempFile);
                                                
                                                // 更新视频URL
                                                $video['originVideo']['filePath'] = $ossUrl;
                                            } finally {
                                                // 清理临时文件
                                                @unlink($tempFile);
                                            }
                                        }
                                        $processedVideos[] = $video;
                                    }
                                    
                                    $apiResult['videos'] = $processedVideos;
                                    $updateData['result_videos'] = json_encode($apiResult['videos']);
                                    $updateData['cost_credit'] = $apiResult['costCredit'] ?? 0;
                                }
                                $statusChanged = true;
                                $videoSuccessCount++;
                                $output->writeln('  -> 视频生成成功');
                                break;
                            case 'fail':
                                $updateData['status'] = 6; // 图转视频失败
                                $updateData['error_msg'] = $apiResult['message'] ?? $apiResult['errorMsg'] ?? '视频生成失败';
                                $statusChanged = true;
                                $videoFailedCount++;
                                $output->writeln('  -> 视频生成失败: ' . $updateData['error_msg']);
                                break;
                            case 'processing':
                                $output->writeln('  -> 视频仍在生成中');
                                break;
                            default:
                                $output->writeln('  -> 未知状态: ' . $apiResult['status']);
                                break;
                        }
                    }
                    // 更新数据库
                    if (!empty($updateData)) {
                        Db::name('product_anyshoot_tasks')
                            ->where('id', $task['id'])
                            ->update($updateData);
                        $videoUpdatedCount++;
                    }
                    // 记录日志
                    if ($statusChanged) {
                        Log::info('ProductAnyShoot视频任务状态更新', [
                            'task_id' => $task['task_id'],
                            'video_task_id' => $task['video_task_id'],
                            'old_status' => $task['status'],
                            'old_status_text' => $this->getStatusText($task['status']),
                            'new_status' => $updateData['status'] ?? $task['status'],
                            'new_status_text' => $this->getStatusText($updateData['status'] ?? $task['status']),
                            'api_status' => $apiResult['status'] ?? 'unknown'
                        ]);
                    }
                } catch (\Exception $e) {
                    $output->writeln('  -> 检查视频任务失败: ' . $e->getMessage());
                    Log::error('检查ProductAnyShoot视频任务状态失败', [
                        'task_id' => $task['task_id'],
                        'video_task_id' => $task['video_task_id'],
                        'error' => $e->getMessage()
                    ]);
                }
                sleep(1);
            }

            $output->writeln("视频任务检查: 共" . count($videoTasks) . "个，更新" . $videoUpdatedCount . "个，成功" . $videoSuccessCount . "个，失败" . $videoFailedCount . "个");
            
        } catch (\Exception $e) {
            $output->writeln('执行失败: ' . $e->getMessage());
            Log::error('ProductAnyShoot任务状态检查脚本执行失败', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
        }
    }
    
    /**
     * 获取状态文本描述
     */
    private function getStatusText($status)
    {
        $statusTexts = [
            0 => '待处理',
            1 => '图片生成中',
            2 => '图片生成失败',
            3 => '等待图转视频',
            4 => '图转视频中',
            5 => '图转视频成功',
            6 => '图转视频失败'
        ];
        
        return $statusTexts[$status] ?? '未知状态';
    }

    /**
     * 使用cURL下载视频文件，带重试机制
     * @param string $url 下载URL
     * @param int $maxRetries 最大重试次数
     * @return string|false 文件内容或false
     */
    private function downloadVideoWithRetry($url, $maxRetries = 10)
    {
        for ($attempt = 1; $attempt <= $maxRetries; $attempt++) {
            try {
                $ch = curl_init();
                curl_setopt_array($ch, [
                    CURLOPT_URL => $url,
                    CURLOPT_RETURNTRANSFER => true,
                    CURLOPT_FOLLOWLOCATION => true,
                    CURLOPT_MAXREDIRS => 10,
                    CURLOPT_TIMEOUT => 300, // 5分钟超时，视频文件可能较大
                    CURLOPT_CONNECTTIMEOUT => 30,
                    CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
                    CURLOPT_SSL_VERIFYPEER => false,
                    CURLOPT_SSL_VERIFYHOST => false,
                    CURLOPT_HEADER => false,
                    CURLOPT_HTTPHEADER => [
                        'Accept: */*',
                        'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8',
                        'Accept-Encoding: gzip, deflate, br',
                        'Connection: keep-alive',
                        'Upgrade-Insecure-Requests: 1'
                    ],
                    CURLOPT_ENCODING => '', // 自动解压
                ]);

                // 检查是否有代理设置
                $proxy = getenv('https_proxy') ?: getenv('http_proxy');
                if ($proxy) {
                    curl_setopt($ch, CURLOPT_PROXY, $proxy);
                    curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
                }

                $content = curl_exec($ch);
                $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                $error = curl_error($ch);
                curl_close($ch);

                if ($content === false || !empty($error)) {
                    throw new \Exception("cURL错误: " . $error);
                }

                if (in_array($httpCode, [200, 206])) {
                    return $content;
                } else {
                    throw new \Exception("HTTP错误: " . $httpCode);
                }

            } catch (\Exception $e) {
                if ($attempt === $maxRetries) {
                    \think\facade\Log::error('下载视频失败', [
                        'url' => $url,
                        'attempt' => $attempt,
                        'error' => $e->getMessage()
                    ]);
                    return false;
                }
                
                // 指数退避重试
                // $delay = pow(2, $attempt - 1);
                // sleep($delay);
            }
        }
        
        return false;
    }

    /**
     * 使用cURL下载图片文件，带重试机制
     * @param string $url 下载URL
     * @param int $maxRetries 最大重试次数
     * @return string|false 文件内容或false
     */
    private function downloadImageWithRetry($url, $maxRetries = 10)
    {
        for ($attempt = 1; $attempt <= $maxRetries; $attempt++) {
            try {
                $ch = curl_init();
                curl_setopt_array($ch, [
                    CURLOPT_URL => $url,
                    CURLOPT_RETURNTRANSFER => true,
                    CURLOPT_FOLLOWLOCATION => true,
                    CURLOPT_MAXREDIRS => 10,
                    CURLOPT_TIMEOUT => 60,
                    CURLOPT_CONNECTTIMEOUT => 30,
                    CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
                    CURLOPT_SSL_VERIFYPEER => false,
                    CURLOPT_SSL_VERIFYHOST => false,
                    CURLOPT_HEADER => false,
                    CURLOPT_HTTPHEADER => [
                        'Accept: image/webp,image/apng,image/*,*/*;q=0.8',
                        'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8',
                        'Accept-Encoding: gzip, deflate, br',
                        'Connection: keep-alive',
                        'Upgrade-Insecure-Requests: 1'
                    ],
                    CURLOPT_ENCODING => '', // 自动解压
                ]);

                // 检查是否有代理设置
                $proxy = getenv('https_proxy') ?: getenv('http_proxy');
                if ($proxy) {
                    curl_setopt($ch, CURLOPT_PROXY, $proxy);
                    curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
                }

                $content = curl_exec($ch);
                $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                $error = curl_error($ch);
                curl_close($ch);

                if ($content === false || !empty($error)) {
                    throw new \Exception("cURL错误: " . $error);
                }

                if (in_array($httpCode, [200, 206])) {
                    return $content;
                } else {
                    throw new \Exception("HTTP错误: " . $httpCode);
                }

            } catch (\Exception $e) {
                if ($attempt === $maxRetries) {
                    \think\facade\Log::error('下载图片失败', [
                        'url' => $url,
                        'attempt' => $attempt,
                        'error' => $e->getMessage()
                    ]);
                    return false;
                }
                
                // 指数退避重试
                $delay = pow(2, $attempt - 1);
                sleep($delay);
            }
        }
        
        return false;
    }
} 